package com.atguigu.tingshu.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.tingshu.account.client.UserAccountFeignClient;
import com.atguigu.tingshu.album.client.AlbumInfoFeignClient;
import com.atguigu.tingshu.album.client.TrackInfoFeignClient;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.order.OrderDerate;
import com.atguigu.tingshu.model.order.OrderDetail;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.model.user.UserInfo;
import com.atguigu.tingshu.model.user.VipServiceConfig;
import com.atguigu.tingshu.order.helper.SignHelper;
import com.atguigu.tingshu.order.mapper.OrderDerateMapper;
import com.atguigu.tingshu.order.mapper.OrderDetailMapper;
import com.atguigu.tingshu.order.mapper.OrderInfoMapper;
import com.atguigu.tingshu.order.service.OrderInfoService;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.user.client.VipServiceConfigFeignClient;
import com.atguigu.tingshu.vo.account.AccountLockVo;
import com.atguigu.tingshu.vo.order.OrderDerateVo;
import com.atguigu.tingshu.vo.order.OrderDetailVo;
import com.atguigu.tingshu.vo.order.OrderInfoVo;
import com.atguigu.tingshu.vo.order.TradeVo;
import com.atguigu.tingshu.vo.user.UserPaidRecordVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private UserInfoFeignClient userInfoFeignClient;

    @Autowired
    private AlbumInfoFeignClient albumInfoFeignClient;

    @Autowired
    private VipServiceConfigFeignClient vipServiceConfigFeignClient;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private TrackInfoFeignClient trackInfoFeignClient;

    @Autowired
    private UserAccountFeignClient userAccountFeignClient;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private RabbitService rabbitService;

    @Autowired
    private OrderDerateMapper orderDerateMapper;


    @Override
    public OrderInfoVo trade(TradeVo tradeVo, Long userId) {
        //获取用户信息
        Result<UserInfo> userInfoResult = userInfoFeignClient.getUserInfo(userId);
        Assert.notNull(userInfoResult, "用户结果集不存在");
        UserInfo userInfo = userInfoResult.getData();
        Assert.notNull(userInfo, "用户不存在");
        //  订单原始金额
        BigDecimal originalAmount = new BigDecimal("0.00");
        //  减免总金额
        BigDecimal derateAmount = new BigDecimal("0.00");
        //  订单总金额
        BigDecimal orderAmount = new BigDecimal("0.00");
        //  订单明细列表
        List<OrderDetailVo> orderDetailVoList = new ArrayList<>();
        //  订单减免明细列表
        List<OrderDerateVo> orderDerateVoList = new ArrayList<>();
        //1001-专辑 1002-声音 1003-vip会员
        if (tradeVo.getItemType().equals(SystemConstant.ORDER_ITEM_TYPE_ALBUM)) {
            //判断用户是否购买过专辑
            Result<Boolean> isPaidAlbumResult = userInfoFeignClient.isPaidAlbum(tradeVo.getItemId());
            Assert.notNull(isPaidAlbumResult, "购买结果集不存在");
            Boolean isPaidAlbum = isPaidAlbumResult.getData();
            Assert.notNull(isPaidAlbum, "购买结果不存在");
            if (isPaidAlbum) {
                throw new GuiguException(ResultCodeEnum.REPEAT_BUY_ERROR);
            }
            //用户没有购买过专辑
            //跟据专辑Id查询专辑信息
            Result<AlbumInfo> albumInfoResult = albumInfoFeignClient.getAlbumInfo(tradeVo.getItemId());
            Assert.notNull(albumInfoResult, "专辑结果集不存在");
            AlbumInfo albumInfo = albumInfoResult.getData();
            Assert.notNull(albumInfo, "专辑不存在");
            //判断当前用户是否是vip会员
            if (userInfo.getIsVip().intValue() == 0) {
                //用户不是vip会员
                originalAmount = albumInfo.getPrice();
                //判断是否打折,不等于-1就是打折
                if (albumInfo.getDiscount().intValue() != -1) {
                    //打折 100 8 100*0.8
                    //albumInfo.getDiscount() - 获取专辑的折扣值（例如：8表示8折）
                    //new BigDecimal("10").subtract(albumInfo.getDiscount()) - 计算折扣差值（例如：10-8=2）
                    //originalAmount.multiply(...) - 原始金额乘以折扣差值
                    //.divide(new BigDecimal(10),2, RoundingMode.HALF_UP) - 除以10并保留2位小数，四舍五入
                    derateAmount = originalAmount.multiply(new BigDecimal("10").subtract(albumInfo.getDiscount()))
                            .divide(new BigDecimal(10), 2, RoundingMode.HALF_UP);
                }
                //订单总价
                orderAmount = originalAmount.subtract(derateAmount);
            } else {
                //用户是vip会员
                originalAmount = albumInfo.getPrice();
                //判断是否打折,不等于-1就是打折
                if (albumInfo.getVipDiscount().intValue() != -1) {
                    derateAmount = albumInfo.getPrice().multiply(new BigDecimal(10).subtract(
                            albumInfo.getVipDiscount())).divide(new BigDecimal(10), 2, RoundingMode.HALF_UP);
                }
                //订单总价
                orderAmount = originalAmount.subtract(derateAmount);
            }
            //订单明细
            OrderDetailVo orderDetailVo = new OrderDetailVo();
            orderDetailVo.setItemId(albumInfo.getId());
            orderDetailVo.setItemName(albumInfo.getAlbumTitle());
            orderDetailVo.setItemUrl(albumInfo.getCoverUrl());
            orderDetailVo.setItemPrice(albumInfo.getPrice());
            orderDetailVoList.add(orderDetailVo);

            //订单减免明细
            if (originalAmount.subtract(derateAmount).doubleValue() != 0) {
                OrderDerateVo orderDerateVo = new OrderDerateVo();
                orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_ALBUM_DISCOUNT);
                orderDerateVo.setDerateAmount(originalAmount.subtract(orderAmount));
                orderDerateVoList.add(orderDerateVo);
            }
        } else if (tradeVo.getItemType().equals(SystemConstant.ORDER_ITEM_TYPE_TRACK)) {
            //1002-声音
            //判断
            if (tradeVo.getTrackCount() < 0) {
                throw new GuiguException(ResultCodeEnum.ARGUMENT_VALID_ERROR);
            }
            //获取下单声音列表
            Result<List<TrackInfo>> paidTrackInfoListResult = trackInfoFeignClient.findPaidTrackInfoList(tradeVo.getItemId(), tradeVo.getTrackCount());
            Assert.notNull(paidTrackInfoListResult, "声音结果集不存在");
            List<TrackInfo> paidTrackInfoList = paidTrackInfoListResult.getData();
            Assert.notNull(paidTrackInfoList, "声音列表不存在");
            //购买声音不支持折扣
            Result<AlbumInfo> albumInfoResult = albumInfoFeignClient.getAlbumInfo(paidTrackInfoList.get(0).getAlbumId());
            Assert.notNull(albumInfoResult, "专辑结果集不存在");
            AlbumInfo albumInfo = albumInfoResult.getData();
            Assert.notNull(albumInfo, "专辑不存在");
            originalAmount = tradeVo.getTrackCount().intValue() > 0 ? albumInfo.getPrice()
                    .multiply(new BigDecimal(tradeVo.getTrackCount())) : albumInfo.getPrice();
            //计算订单总价
            orderAmount = originalAmount;

            //循环遍历声音集合对象赋值订单明细
            orderDetailVoList = paidTrackInfoList.stream().map(trackInfo -> {
                OrderDetailVo orderDetailVo = new OrderDetailVo();
                orderDetailVo.setItemId(trackInfo.getId());
                orderDetailVo.setItemName(trackInfo.getTrackTitle());
                orderDetailVo.setItemUrl(trackInfo.getCoverUrl());
                orderDetailVo.setItemPrice(albumInfo.getPrice());
                return orderDetailVo;
            }).collect(Collectors.toList());
        } else {
            //  根据id 获取VIP 服务配置信息
            Result<VipServiceConfig> vipServiceConfigResult = vipServiceConfigFeignClient.getVipServiceConfig(tradeVo.getItemId());
            Assert.notNull(vipServiceConfigResult, "VIP服务结果集不存在");
            VipServiceConfig vipServiceConfig = vipServiceConfigResult.getData();
            Assert.notNull(vipServiceConfig, "VIP服务不存在");

            originalAmount = vipServiceConfig.getPrice();
            derateAmount = vipServiceConfig.getPrice().subtract(vipServiceConfig.getDiscountPrice());
            orderAmount = originalAmount.subtract(derateAmount);

            //订单明细
            OrderDetailVo orderDetailVo = new OrderDetailVo();
            orderDetailVo.setItemId(vipServiceConfig.getId());
            orderDetailVo.setItemName("VIP会员" + vipServiceConfig.getName());
            orderDetailVo.setItemUrl(vipServiceConfig.getImageUrl());
            orderDetailVo.setItemPrice(vipServiceConfig.getPrice());
            orderDetailVoList.add(orderDetailVo);

            //订单减免明细
            if (originalAmount.subtract(derateAmount).doubleValue() != 0) {
                OrderDerateVo orderDerateVo = new OrderDerateVo();
                orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_VIP_SERVICE_DISCOUNT);
                orderDerateVo.setDerateAmount(originalAmount.subtract(orderAmount));
                orderDerateVoList.add(orderDerateVo);
            }
        }
        //防重,生成一个唯一标识,保存到redis中一份
        String tradeNoKey = "user:trade:" + userId;
        //定义一个流水号
        String tradeNo = UUID.randomUUID().toString().replace("-", "");
        redisTemplate.opsForValue().set(tradeNoKey, tradeNo);

        //构造结果
        OrderInfoVo orderInfoVo = new OrderInfoVo();
        orderInfoVo.setItemType(tradeVo.getItemType());
        orderInfoVo.setOriginalAmount(originalAmount);
        orderInfoVo.setDerateAmount(derateAmount);
        orderInfoVo.setOrderAmount(orderAmount);
        orderInfoVo.setTradeNo(tradeNo);
        orderInfoVo.setOrderDetailVoList(orderDetailVoList);
        orderInfoVo.setOrderDerateVoList(orderDerateVoList);
        orderInfoVo.setTimestamp(SignHelper.getTimestamp());

        // 支付方式默认值 目的是防止用户在前端篡改金额数据
        orderInfoVo.setPayWay(SystemConstant.ORDER_PAY_WAY_WEIXIN);
        // 生成签名
        Map<String, Object> parameterMap = JSON.parseObject(JSON.toJSONString(orderInfoVo), Map.class);
        // {"orderDerateVoList":[{"derateType":"1406","derateAmount":20.00}],"itemType":"1003","orderAmount":40.00,
        // "originalAmount":60.00,"tradeNo":"ed2628826ba54ebfa41632f9173a780d","derateAmount":20.00,
        // "payWay":"","orderDetailVoList":[{"itemId":2,"itemName":"购买VIP3个月","itemPrice":40.00,
        // "itemUrl":"http://39.98.123.211/group1/vip.png"}],"timestamp":1699606865851}
        String sign = SignHelper.getSign(parameterMap);
        orderInfoVo.setSign(sign);
        //返回结果
        return orderInfoVo;
    }
    @GlobalTransactional(rollbackFor = Exception.class)
    @Override
    public String submitOrder(OrderInfoVo orderInfoVo, Long userId) {
        //  校验签名
        Map map = JSON.parseObject(JSON.toJSONString(orderInfoVo), Map.class);
        map.put("payWay", SystemConstant.ORDER_PAY_WAY_WEIXIN);
        SignHelper.checkSign(map);

        //  验证校验好，防止重复提交订单
        String tradeNo = orderInfoVo.getTradeNo();
        if (ObjectUtils.isEmpty(tradeNo)) {
            //  非法请求
            throw new GuiguException(ResultCodeEnum.ILLEGAL_REQUEST);
        }
        String tradeNoKey = "user:trade:" + userId;
        String script = "if(redis.call('get', KEYS[1]) == ARGV[1]) then return redis.call('del', KEYS[1]) else return 0 end";
        Boolean flag = (Boolean) redisTemplate.execute(new DefaultRedisScript<>(script, Boolean.class), Arrays.asList(tradeNoKey), tradeNo);
        if (!flag) {
            //  不能重复提交
            throw new GuiguException(ResultCodeEnum.ORDER_SUBMIT_REPEAT);
        }
        //3.下单
        //使用交易号座位订单号,或重新生成订单号
        String orderNo = UUID.randomUUID().toString().replace("-", "");
        //支付类型
        if (!SystemConstant.ORDER_PAY_ACCOUNT.equals(orderInfoVo.getPayWay())) {
            //在线支付
            this.saveOrder(orderInfoVo, userId, orderNo);
        } else {
            try {
                //余额支付
                //锁定账户可用余额
                AccountLockVo accountLockVo = new AccountLockVo();
                accountLockVo.setOrderNo(orderNo);
                accountLockVo.setUserId(userId);
                accountLockVo.setAmount(orderInfoVo.getOrderAmount());
                accountLockVo.setContent(orderInfoVo.getOrderDetailVoList().get(0).getItemName());
                //检查与锁定账户金额
                Result result = userAccountFeignClient.checkAndLock(accountLockVo);
                if (200 != result.getCode()) {
                    throw new GuiguException(result.getCode(), result.getMessage());
                }
                //保存订单
                this.saveOrder(orderInfoVo, userId, orderNo);
                //创建用户购买记录对象
                UserPaidRecordVo userPaidRecordVo = new UserPaidRecordVo();
                //记录用户购买信息
                userPaidRecordVo.setOrderNo(orderNo);
                userPaidRecordVo.setUserId(userId);
                userPaidRecordVo.setItemType(orderInfoVo.getItemType());
                //  购买项目的Id 专辑Id，声音Id, 服务配置Id: 在哪? order_detail.item_id
                List<Long> itemIdList = orderInfoVo.getOrderDetailVoList().stream().map(OrderDetailVo::getItemId).collect(Collectors.toList());
                userPaidRecordVo.setItemIdList(itemIdList);
                //远程调用
                Result userResult = userInfoFeignClient.userPayRecord(userPaidRecordVo);
                //判断
                if (200 != userResult.getCode()) {
                    throw new GuiguException(211, "新增购买记录异常");
                }
                //返回订单编号
                return orderNo;
            } catch (GuiguException e) {
                log.error(e.getMessage(), e);
                //  抛出异常
                throw new GuiguException(e.getCode(), e.getMessage());
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                // 抛出异常
                throw new GuiguException(ResultCodeEnum.DATA_ERROR);
            }
        }
        return orderNo;
    }

    @Transactional
    @Override
    public OrderInfo saveOrder(OrderInfoVo orderInfoVo, Long userId, String orderNo) {
        //创建对象
        OrderInfo orderInfo = new OrderInfo();
        //属性拷贝
        BeanUtils.copyProperties(orderInfoVo, orderInfo);
        orderInfo.setOrderNo(orderNo);
        String orderTitle = orderInfoVo.getOrderDetailVoList().get(0).getItemName();
        orderInfo.setOrderTitle(orderTitle);
        orderInfo.setUserId(userId);
        orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_UNPAID);
        //保存订单
        orderInfoMapper.insert(orderInfo);

        //保存订单明细
        if (!CollectionUtils.isEmpty(orderInfoVo.getOrderDetailVoList())) {
            orderInfoVo.getOrderDetailVoList().forEach(orderDetailVo -> {
                OrderDetail orderDetail = new OrderDetail();
                BeanUtils.copyProperties(orderDetailVo, orderDetail);
                orderDetail.setOrderId(orderInfo.getId());
                orderDetailMapper.insert(orderDetail);
            });
        }

        //保存订单减免明细
        if (!CollectionUtils.isEmpty(orderInfoVo.getOrderDerateVoList())) {
            orderInfoVo.getOrderDerateVoList().forEach(orderDerateVo -> {
                OrderDerate orderDerate = new OrderDerate();
                BeanUtils.copyProperties(orderDerateVo, orderDerate);
                orderDerate.setOrderId(orderInfo.getId());
                orderDerateMapper.insert(orderDerate);
            });
        }
        //订单支付方式1101-微信 1102-支付宝 1103-账户余额
        if (SystemConstant.ORDER_PAY_ACCOUNT.equals(orderInfoVo.getPayWay())) {
            //余额支付成功保存交易数据
            this.orderPaySuccess(orderNo);
        } else {
            // 发送延迟队列，如果定时未支付，取消订单
            rabbitService.sendDealyMessage(MqConst.EXCHANGE_CANCEL_ORDER, MqConst.ROUTING_CANCEL_ORDER, orderInfo.getId(), MqConst.CANCEL_ORDER_DELAY_TIME);
        }
        return orderInfo;
    }

    @Override
    public void orderPaySuccess(String orderNo) {
        //  查询对象
        //  OrderInfo orderInfo = this.getOne(new LambdaQueryWrapper<OrderInfo>().eq(OrderInfo::getOrderNo, orderNo));
        OrderInfo orderInfo = this.getOrderInfoByOrderNo(orderNo);
       //如果已经修改为支付,那么就不需要再修改了
        if(SystemConstant.ORDER_STATUS_PAID.equals(orderInfo.getOrderStatus()))return;
        //赋值为已支付
        orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_PAID);
        //修改状态
        this.updateById(orderInfo);
        //记录用户购买信息:微信支付就需要再次调用:余额支付不需要
        if(SystemConstant.ORDER_PAY_WAY_WEIXIN.equals(orderInfo.getPayWay())){
            //  添加一个判断：
            //  保存用户购买记录：
            UserPaidRecordVo userPaidRecordVo = new UserPaidRecordVo();
            userPaidRecordVo.setOrderNo(orderNo);
            userPaidRecordVo.setUserId(orderInfo.getUserId());
            userPaidRecordVo.setItemType(orderInfo.getItemType());
            //  [专辑Id;vip服务配置Id;下单的时候只能购买一个，这个明细数据就是一条] 声音Id{应该是集合}
            //  以上Id都在? orderInfoVo.getOrderDetailVoList(); 订单明细表中有itemId;
            //  List<Long> itemIdList = orderInfoVo.getOrderDetailVoList().stream().map(OrderDetailVo::getItemId).collect(Collectors.toList());
            //  声音只支持余额支付！
            List<Long> itemIdList = orderInfo.getOrderDetailList().stream().map(OrderDetail::getItemId).collect(Collectors.toList());
            //远程调用保存用户交易记录
            this.userInfoFeignClient.userPayRecord(userPaidRecordVo);
        }
    }

    /**
     * 根据订单orderNo 获取订单对象
     *
     * @param orderNo
     * @return
     */
    public OrderInfo getOrderInfoByOrderNo(String orderNo) {
        //获取订单对象
        OrderInfo orderInfo = this.getOne(new LambdaQueryWrapper<OrderInfo>().eq(OrderInfo::getOrderNo, orderNo));
        //查看订单明细
        List<OrderDetail> orderDetailList = orderDetailMapper.selectList(new LambdaQueryWrapper<OrderDetail>()
                .eq(OrderDetail::getOrderId, orderInfo.getId()));

        //赋值订单明细
        orderInfo.setOrderDetailList(orderDetailList);
        orderInfo.setPayWayName(this.getPayWayName(orderInfo.getPayWay()));
        //返回数据
        return orderInfo;
    }

    private String getPayWayName(String payWay) {
        //声明一个对象
        return SystemConstant.ORDER_PAY_WAY_WEIXIN.equals(payWay) ? "微信支付" : "余额支付";
    }

    @Override
    public void orderCancel(Long orderId) {
        // 设置更新数据
        OrderInfo orderInfoUpt = new OrderInfo();
        orderInfoUpt.setId(orderId);
        orderInfoUpt.setOrderStatus(SystemConstant.ORDER_STATUS_CANCEL);
        // 执行更新方法
        this.updateById(orderInfoUpt);
    }

    @Override
    public IPage<OrderInfo> findUserPage(IPage<OrderInfo> ipage, Long userId, String orderStatus) {
        //调用mapper层方法
        IPage<OrderInfo> infoIPage = orderInfoMapper.selectUserPage(ipage, userId, orderStatus);
        infoIPage.getRecords().forEach(orderInfo -> {
            //  赋值订单状态名称
            String orderStatusName = orderInfo.getOrderStatus().equals(SystemConstant.ORDER_STATUS_UNPAID) ? "未支付" : orderInfo.getOrderStatus().equals(SystemConstant.ORDER_STATUS_PAID) ? "已支付" : "取消";
            orderInfo.setOrderStatusName(orderStatusName);
            orderInfo.setPayWayName(orderInfo.getPayWay().equals(SystemConstant.ORDER_PAY_ACCOUNT) ? "余额" : "在线");
        });
        return infoIPage;
    }

    /**
     * 根据订单状态获取到订单名称
     *
     * @param orderStatus
     * @return
     */
    private String getOrderStatusName(String orderStatus) {
        //声明订单状态名称
        String orderStatusName = "";
        //判断
        if (SystemConstant.ORDER_STATUS_UNPAID.equals(orderStatus)) {
            orderStatusName = "待支付";
        } else if (SystemConstant.ORDER_STATUS_PAID.equals(orderStatus)) {
            orderStatusName = "已支付";
        } else {
            orderStatusName = "已取消";
        }
        //返回
        return orderStatusName;
    }
}
